#include <ctime>

#include "../net_common.h"
#include "network_message_handler.h"
#include "protobuf/heart_beat.pb.h"
#include "protobuf/user_login.pb.h"
#include "protobuf/user_register.pb.h"
#include "protobuf/user_start_matching.pb.h"
#include "protobuf/user_stop_matching.pb.h"
#include "protobuf/game_init.pb.h"
#include "protobuf/left_button_clicked.pb.h"
#include "protobuf/game_over.pb.h"

#include "user_manager.h"
#include "matching.h"
#include "game_manager.h"

std::string time_stamp_to_string(std::time_t time_stamp) {
    // 将 time_t 转换为 tm 结构（本地时间）
    std::tm* local_time = std::localtime(&time_stamp);

    // 定义缓冲区来存储格式化后的时间字符串
    char buffer[100];

    // 格式化时间为可读的字符串
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local_time);

    // 返回格式化后的字符串
    return std::string(buffer);
}

/**
 * @brief: 心跳消息处理
 * @details: 客户端与服务器端建立连接(session)后，客户端每隔一段时间发送一个心跳消息到服务器端，服务器端接收到心跳消息后，\
 *      回复一个心跳消息到客户端，
 */
int network_message_handler::message_handler_heart_beat(std::shared_ptr<session> session, const network_message& msg)
{
    HeartBeatC2SProto heart_beat_from_client;
    bool parse_result = heart_beat_from_client.ParseFromString(msg.data_);
    if (!parse_result) {
        return NET_EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a heart beat msg from client: " << heart_beat_from_client.DebugString() << std::endl;

    HeartBeatS2CProto heart_beat_to_client;
    heart_beat_to_client.set_timestamp(time(nullptr));
    heart_beat_to_client.set_sequence(heart_beat_from_client.sequence());

    auto send_msg_str = heart_beat_to_client.SerializeAsString();
    network_message send_msg(MSG_TYPE_S2C_HEARTBEAT, send_msg_str);

    return NET_EC_OK;
}

int network_message_handler::message_handler_user_login(std::shared_ptr<session> session, const network_message& msg)
{
    UserLoginC2SProto user_login_from_client;
    bool parse_result = user_login_from_client.ParseFromString(msg.data_);
    if (!parse_result) {
        return NET_EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a user login msg from client: " << user_login_from_client.DebugString() << std::endl;

    auto &user_mgr = user_manager::get_instance();

    UserLoginS2CProto user_login_to_client;

    uint32_t uid = 0;
    int ret = user_mgr.user_login(session, user_login_from_client.name(), user_login_from_client.password(), uid);
    if (ret == NET_EC_OK) {
        user_login_to_client.set_login_result(LoginSuccess);
        user_login_to_client.set_uid(uid);
    } else if (ret == NET_EC_NOT_FOUND) {
        user_login_to_client.set_login_result(UserNotExist);
        user_login_to_client.set_error_msg("user name or password error");
    } else if (ret == NET_EC_PASSWORD_ERROR) {
        user_login_to_client.set_login_result(PasswordError);
        user_login_to_client.set_error_msg("user name or password error");
    } else {
        user_login_to_client.set_login_result(LoginOtherError);
        user_login_to_client.set_error_msg("user login unknown error");
    }
    user_login_to_client.set_user_name(user_login_from_client.name());
    std::cout << "send msg proto: " << user_login_to_client.DebugString() << std::endl;

    network_message send_msg(MSG_TYPE_S2C_USER_LOGIN, user_login_to_client.SerializeAsString());
    session->send_message(send_msg.to_string());

    return NET_EC_OK;
}

int network_message_handler::message_handler_user_register(std::shared_ptr<session> session, const network_message& msg)
{
    UserRegisterC2SProto user_register_from_client;
    bool parse_result = user_register_from_client.ParseFromString(msg.data_);
    if (!parse_result) {
        return NET_EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a user register msg from client: " << user_register_from_client.DebugString() << std::endl;

    auto &user_mgr = user_manager::get_instance();

    uint32_t uid = 0;
    UserRegisterS2CProto user_register_to_client;
    int ret = user_mgr.user_signup(user_register_from_client.name(), user_register_from_client.password(), uid);
    if (ret == NET_EC_OK) {
        user_register_to_client.set_register_result(RegisterSuccess);
        user_register_to_client.set_uid(uid);
    } else if (ret == NET_EC_ALREADY_EXIST) {
        user_register_to_client.set_register_result(UserNameExist);
        user_register_to_client.set_error_msg("user name already exist");
    } else {
        user_register_to_client.set_register_result(RegisterOtherError);
        user_register_to_client.set_error_msg("user register unknown error");
    }

    network_message send_msg(MSG_TYPE_S2C_USER_REGISTER, user_register_to_client.SerializeAsString());
    session->send_message(send_msg.to_string());

    return NET_EC_OK;
}

int network_message_handler::message_handler_user_start_matching(std::shared_ptr<session> session,
    const network_message& msg)
{
    UserStartMatchingC2SProto user_start_matching_from_client;
    bool parse_result = user_start_matching_from_client.ParseFromString(msg.data_);
    if (!parse_result) {
        return NET_EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a user start matching msg from client: " << user_start_matching_from_client.DebugString()
        << std::endl;

    UserStartMatcingS2CProto user_start_matching_to_client;
    auto &mt = matching::get_instance();
    std::vector<uint32_t> users;
    auto match_ret = mt.player_join_in(user_start_matching_from_client.uid(), users);
    if (match_ret == matching::MATCHING_SUCCESS) {
        /* 向双方玩家客户端发送匹配成功消息 */
        user_start_matching_to_client.set_result(UserStartMatchingResult::UserStartMatcingSuccess);
        user_start_matching_to_client.set_uid1(users[0]);
        user_start_matching_to_client.set_uid2(users[1]);

        network_message send_msg(MSG_TYPE_S2C_START_MATCHING, user_start_matching_to_client.SerializeAsString());

        auto &um = user_manager::get_instance();
        auto session1 = um.get_session_by_uid(users[0]);
        auto session2 = um.get_session_by_uid(users[1]);

        if ((session1 == nullptr) || (session2 == nullptr)) {
            return NET_EC_MATCHING_ERROR;
        }
        session1->send_message(send_msg.to_string());
        session2->send_message(send_msg.to_string());

        /* 匹配成功开始游戏 */
        auto &game_mgr = game_manager::get_instance();
        std::vector<pos> bombs_pos;
        std::vector<pos> pos_opened_by_system;
        (void)game_mgr.start_game(users[0], users[1], bombs_pos, pos_opened_by_system);

        /* 将游戏初始化数据发送给玩家 */
        GameInitS2CProto game_init_to_client;
        for (const auto &p : bombs_pos) {
            ::GameInitS2CProto_Pos* bomb = game_init_to_client.add_bombs();
            bomb->set_row(p.row());
            bomb->set_col(p.col());
        }
        for (const auto &p : pos_opened_by_system) {
            ::GameInitS2CProto_Pos* pos = game_init_to_client.add_positions();
            pos->set_row(p.row());
            pos->set_col(p.col());
        }
        network_message send_msg2(MSG_TYPE_S2C_GAME_INIT, game_init_to_client.SerializeAsString());
        session1->send_message(send_msg2.to_string());
        session2->send_message(send_msg2.to_string());
    } else if (match_ret == matching::MATCHING_WATING_FOR_PLAYER) {
        user_start_matching_to_client.set_result(UserStartMatchingResult::UserStartMatcingWaitingForPlayer);
        network_message send_msg(MSG_TYPE_S2C_START_MATCHING, user_start_matching_to_client.SerializeAsString());
        session->send_message(send_msg.to_string());
    } else {
        user_start_matching_to_client.set_result(UserStartMatchingResult::UserStartMatcingFailed);
        network_message send_msg(MSG_TYPE_S2C_START_MATCHING, user_start_matching_to_client.SerializeAsString());
        session->send_message(send_msg.to_string());
    }

    return NET_EC_OK;
}

int network_message_handler::message_handler_user_stop_matching(std::shared_ptr<session> session,
    const network_message& msg)
{
    uint32_t ret;
    UserStopMatcingC2SProto user_stop_matching_from_client;
    bool parse_result = user_stop_matching_from_client.ParseFromString(msg.data_);
    if (!parse_result) {
        return NET_EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a user stop matching msg from client: " << user_stop_matching_from_client.DebugString()
        << std::endl;

    auto &mt = matching::get_instance();

    ret = mt.player_leave(user_stop_matching_from_client.uid());
    if (ret != NET_EC_OK) {
        std::cout << "user leave matching failed, uid: " << user_stop_matching_from_client.uid() << std::endl;
    }

    UserStopMatcingS2CProto user_stop_matching_to_client;
    if (ret != NET_EC_OK) {
        user_stop_matching_to_client.set_result(UserStopMatchingResult::UserStopMatcingFailed);
    } else {
        user_stop_matching_to_client.set_result(UserStopMatchingResult::UserStopMatcingSuccess);
    }

    network_message send_msg(MSG_TYPE_S2C_STOP_MATCHING, user_stop_matching_to_client.SerializeAsString());
    session->send_message(send_msg.to_string());

    return NET_EC_OK;
}

int network_message_handler::message_handler_left_button_clicked(std::shared_ptr<session> session,
    const network_message& msg)
{
    uint32_t ret;
    LeftButtonClickedC2SProto left_button_clicked_from_client;
    bool parse_result = left_button_clicked_from_client.ParseFromString(msg.data_);
    if (!parse_result) {
        return NET_EC_PROTOBUF_PARSE_FAILED;
    }

    std::cout << "receive a left button clicked msg from client: " << left_button_clicked_from_client.DebugString()
        << std::endl;
    
    /* 根据session找到uid，再找到进行中的游戏 */
    auto &user_mgr = user_manager::get_instance();
    auto user_ptr = user_mgr.get_user_by_session(session);

    auto &game_mgr = game_manager::get_instance();
    auto game_ptr = game_mgr.get_game(user_ptr->uid());

    std::shared_ptr<player> player = nullptr;

    auto player_index = left_button_clicked_from_client.player_index();
    if (player_index == ::LeftButtonClickedC2SProto_PlayerIndex_Player1) {
        player = game_ptr->p1();
    } else if (player_index == ::LeftButtonClickedC2SProto_PlayerIndex_Player2) {
        player = game_ptr->p2();
    } else {
        std::cout << "invalid player index: " << player_index << std::endl;
        return NET_EC_E_INVALID_PARAM;
    }

    bool if_game_over = false;
    pos pos_clicked;
    pos_clicked.set_row(left_button_clicked_from_client.pos().row());
    pos_clicked.set_col(left_button_clicked_from_client.pos().col());
    std::vector<pos> opened_pos = game_ptr->left_buttom_clicked(player, pos_clicked, if_game_over);

    /* 组装发送给双方玩家的本次鼠标点击后的消息 */
    LeftButtonClickedS2CProto left_button_clicked_to_client;
    left_button_clicked_to_client.set_player_index(static_cast<::LeftButtonClickedS2CProto_PlayerIndex>(player_index));
    left_button_clicked_to_client.set_is_bomb(game_ptr->is_bomb(pos_clicked));
    for (const auto &p : opened_pos) {
        ::Pos* pos_to_add = left_button_clicked_to_client.add_pos();
        pos_to_add->set_row(p.row());
        pos_to_add->set_col(p.col());
    }

    network_message send_msg(MSG_TYPE_S2C_LEFT_BUTTON_CLICKED, left_button_clicked_to_client.SerializeAsString());

    /* 将打开的位置发给双方玩家 */
    auto session1 = game_ptr->p1()->get_user()->get_session();
    auto session2 = game_ptr->p2()->get_user()->get_session();

    auto msg_to_send = send_msg.to_string();
    session1->send_message(msg_to_send);
    session2->send_message(msg_to_send);

    if (!if_game_over) {
        return ret;
    }

    /* 处理游戏结束事件 */
    GameOverS2CProto game_over_to_client;
    game_over_to_client.set_player1_score(game_ptr->p1()->score());
    game_over_to_client.set_player1_score(game_ptr->p2()->score());

    network_message send_msg_game_over(MSG_TYPE_S2C_GAME_OVER, game_over_to_client.SerializeAsString());
    auto msg_to_send_game_over = send_msg_game_over.to_string();
    session1->send_message(msg_to_send_game_over);
    session2->send_message(msg_to_send_game_over);
    return ret;
}

/* 在此处添加消息类型和消息处理方式的映射关系 */
void network_message_handler::init_message_handler_map()
{
    register_message_handler(MSG_TYPE_C2S_HEARTBEAT, &network_message_handler::message_handler_heart_beat);
    register_message_handler(MSG_TYPE_C2S_USER_LOGIN, &network_message_handler::message_handler_user_login);
    register_message_handler(MSG_TYPE_C2S_USER_REGISTER, &network_message_handler::message_handler_user_register);
    register_message_handler(MSG_TYPE_C2S_START_MATCHING, &network_message_handler::message_handler_user_start_matching);
    register_message_handler(MSG_TYPE_C2S_STOP_MATCHING, &network_message_handler::message_handler_user_stop_matching);
    register_message_handler(MSG_TYPE_C2S_LEFT_BUTTON_CLICKED, &network_message_handler::message_handler_left_button_clicked);
}

int network_message_handler::handle_message(std::shared_ptr<session> session, const network_message& msg)
{
    int ret;

    /* 校验check sum */
    if (msg.header_.checksum_ != msg.caculate_checksum()) {
        std::cout << "checksum error, msg type: " << msg.header_.msg_type_ << std::endl;
        return NET_EC_CHECKSUM_ERROR;
    }

    auto it = msg_handler_map_.find(msg.header_.msg_type_);
    if (it == msg_handler_map_.end()) {
        std::cout << "unsupported msg type: " << msg.header_.msg_type_ << std::endl;
        return NET_EC_E_INVALID_PARAM;
    }

    auto func = it->second;
    if (func == nullptr) {
        return NET_EC_E_NULL_PTR;
    }
    
    ret = func(this, session, msg);
    if (ret != NET_EC_OK) {
        return ret;
    }

    return NET_EC_OK;
}
